package com.qfmy.webapp.service.impl.novel;


import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qfmy.common.constant.RedisConstant;
import com.qfmy.model.entity.novel.NovelCategory;
import com.qfmy.model.vo.novel.NovelCategoryVo;

import com.qfmy.webapp.mapper.novel.NovelCategoryMapper;
import com.qfmy.webapp.mapper.novel.NovelMapper;
import com.qfmy.webapp.service.agent.ChatService;
import com.qfmy.webapp.service.novel.NovelCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 清风明月
 * @Package com.qfmy.web.app.service.impl.novel
 * @date 2025/11/13
 * @description 小说类型服务impl
 */
@Slf4j
@Service
public class NovelCategoryServiceImpl implements NovelCategoryService {

    /**
     * 注入小说类型mapper
     */
    @Autowired
    private NovelCategoryMapper novelCategoryMapper;

    /**
     * 注入小说mapper
     */
    @Autowired
    private NovelMapper novelMapper;

    /**
     * 注入chatService
     */
    @Autowired
    private ChatService chatService;

    /**
     * 注入redisTemplate
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 创建对象映射器
     */
    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 获取所有小说类型
     * @return
     */
    @Override
    public List<NovelCategoryVo> getAllCategoryName() {
        // 调用mapper方法
        List<NovelCategory> list = novelCategoryMapper.getAllCategoryName();
        //创建集合
        List<NovelCategoryVo> novelCategoryVoList = new ArrayList<>();
        //判断集合是否为空
        if (list != null) {
            //循环遍历分类对象
            for (NovelCategory novelCategory : list) {
                //创建分类对象
                NovelCategoryVo novelCategoryVo = new NovelCategoryVo();
                //进行对象赋值
                novelCategoryVo.setCategoryId(novelCategory.getCategoryId());
                novelCategoryVo.setCategoryName(novelCategory.getCategoryName());
                novelCategoryVoList.add(novelCategoryVo);
            }
            return novelCategoryVoList;
        }
        return new ArrayList<>();

    }

    /**
     * 根据类型获取小说的分类
     * @param type
     * @return
     */
    @Override
    public List<NovelCategoryVo> getCategoryNameByType(Integer type) {
        // 调用mapper方法
        List<NovelCategory> list = novelCategoryMapper.getCategoryNameByType(type);
        //创建集合
        List<NovelCategoryVo> novelCategoryVoList = new ArrayList<>();
        //判断集合是否为空
        if (list != null) {
            //循环遍历分类对象
            for (NovelCategory novelCategory : list) {
                //创建分类对象
                NovelCategoryVo novelCategoryVo = new NovelCategoryVo();
                //进行对象赋值
                novelCategoryVo.setCategoryId(novelCategory.getCategoryId());
                novelCategoryVo.setCategoryName(novelCategory.getCategoryName());
                novelCategoryVo.setImage(novelCategory.getImage());
                novelCategoryVo.setCount(novelCategory.getCount());
                novelCategoryVoList.add(novelCategoryVo);
            }
            return novelCategoryVoList;
        }
        return Collections.emptyList();
    }

    /**
     * 根据类型获取小说的标签
     * @param type
     * @return
     */
    @Override
    public List<List<String>> getCategoryTagsByType(Integer type) {
        //创建缓存key
        String key = RedisConstant.APP_CATEGORY_TAGS_PREFIX + type;

        //从缓存里面获取数据
        List<List<String>> categoryTags = (List<List<String>>) redisTemplate.opsForValue().get(key);
        //判断缓存是否为空
        if (categoryTags != null) {
            return categoryTags;
        }

        // 根据type获取分类id
        List<Long> categoryIds = novelCategoryMapper.getCategoryIdsByType(type);

        // 获取类型名称（处理null风险：若返回null则用空列表兜底）
        List<String> categoryNames = Optional.ofNullable(novelCategoryMapper.getCategoryNamesByType(type))
                .orElse(Collections.emptyList()); // 避免后续contains()报空指针

        // 判断分类ID集合是否为空
        if (categoryIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 根据分类id获取小说的标签，并过滤掉与categoryNames重合的标签
        List<String> tags = novelMapper.getCategoryTagsByCategoryIds(categoryIds);

        List<String> list = tags.stream()
                .filter(Objects::nonNull) // 过滤null标签字符串
                .flatMap(tagStr -> Arrays.stream(tagStr.split(","))) // 拆分逗号分隔的标签
                .map(String::trim) // 去除标签前后空格
                .filter(tag -> !tag.isEmpty()) // 过滤空标签（如拆分后只剩空格）
                // 新增：过滤掉存在于categoryNames中的标签（核心过滤逻辑）
                .filter(tag -> !categoryNames.contains(tag))
                .collect(Collectors.groupingBy(
                        tag -> tag,
                        Collectors.counting() // 统计标签出现次数（Long类型）
                ))
                .entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue())) // 按次数降序
                .map(Map.Entry::getKey) // 仅提取标签名
                .toList();
        //根据ai获取分类的标签
        List<List<String>> tagsByAi = getTagsByAi(tags);
        //将数据存入缓存
        if (tagsByAi != null) {
            redisTemplate.opsForValue().set(key, tagsByAi,12, TimeUnit.HOURS);
        }
        return tagsByAi;
    }

    /**
     * 根据ai获取分类的标签
     * @param tags
     * @return
     */
    @Nullable
    @Contract(pure = true)
    private List<List<String>> getTagsByAi(List<String> tags) {
        //构建提示词
        String prompt = "请帮我将以下标签按照「情节主题」「故事背景」「角色身份」三个类别分类，每个类别对应一个数组，最终以JSON格式返回。\n" +
                "分类说明：\n" +
                "- 情节主题：与故事核心事件、冲突、发展、情感主线相关的标签（例如：复仇、成长、救赎、爱情纠葛）\n" +
                "- 故事背景：与故事发生的时间、地点、社会环境、时代设定相关的标签（例如：古代宫廷、未来科幻、二战战场、乡村小镇）\n" +
                "- 角色身份：与角色的职业、地位、身份标识相关的标签（例如：医生、国王、刺客、学生）\n" +
                "需分类的标签：" + tags;
       String content = chatService.service( prompt);
        if (content == null || content.trim().isEmpty()) {
            return null; // AI返回为空，直接返回null
        }

        try {
            // 将JSON字符串解析为Map<String, List<String>>
            Map<String, List<String>> tagMap = objectMapper.readValue(
                    content,
                    new TypeReference<Map<String, List<String>>>() {}
            );

            // 按固定顺序提取三个类别的标签
            List<String> themeTags = tagMap.getOrDefault("情节主题", new ArrayList<>());
            List<String> backgroundTags = tagMap.getOrDefault("故事背景", new ArrayList<>());
            List<String> roleTags = tagMap.getOrDefault("角色身份", new ArrayList<>());

            // 组装外层List（顺序：情节主题、故事背景、角色身份）
            List<List<String>> result = new ArrayList<>();
            result.add(themeTags);
            result.add(backgroundTags);
            result.add(roleTags);

            return result;

        } catch (Exception e) {
           log.error("解析AI返回的JSON字符串出错：{}", e.getMessage());
            return null;
        }
    }
}
